package org.nimi317.web_gis.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.nimi317.web_gis.context.SecurityContextHolder;
import org.nimi317.web_gis.data.AreaCodeList;
import org.nimi317.web_gis.entity.TableRange;
import org.nimi317.web_gis.exception.E;
import org.nimi317.web_gis.exception.RException;
import org.nimi317.web_gis.exception.StationQualityExistException;
import org.nimi317.web_gis.form.post.StationRenderPost;
import org.nimi317.web_gis.dao.StationQualityMapper;
import org.nimi317.web_gis.entity.Area;
import org.nimi317.web_gis.entity.StationQuality;
import org.nimi317.web_gis.service.IStationQualityService;
import org.nimi317.web_gis.service.ITableRangeService;
import org.nimi317.web_gis.utils.PageUtils;
import org.nimi317.web_gis.utils.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author nimi317
 * @since 2024-01-03
 */
@Service
@Slf4j
@Transactional
public class StationQualityServiceImpl extends ServiceImpl<StationQualityMapper, StationQuality> implements IStationQualityService {

    @Autowired
    private AreaCodeList areaCodeList;

    @Autowired
    private ThreadPoolTaskExecutor executor;

    private final ITableRangeService rangeService;

    public StationQualityServiceImpl(ITableRangeService rangeService) {
        this.rangeService = rangeService;
    }

    @Override
    public boolean updateQualityData() throws AreaCodeException {
        List<Area> codes = areaCodeList.getAreaCodes();
        if (ObjectUtils.isEmpty(codes)) {
            log.error("获取区域编码失败");
            throw new AreaCodeException();
        }
        AtomicBoolean flag = new AtomicBoolean(true);
        CountDownLatch countDownLatch = new CountDownLatch(codes.size());
        for (Area code : codes) {
            if (flag.get()) {
                executor.execute(() -> {
                    try {
                        areaCodeList.updateStationQuality(code.getCityName(), flag);
                    } catch (StationQualityExistException e) {
                        log.error("更新站点数据失败", e);
                        flag.set(false);
                    } finally {
                        countDownLatch.countDown();
                    }
                });
            } else {
                countDownLatch.countDown();
            }
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return flag.get();
    }

    @Override
    public List<StationQuality> getRecentQualityData(String id) {
        SecurityContextHolder.setTableName(areaCodeList.getTableName());
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationQuality::getStationCode, id)
                .le(StationQuality::getTimestamp, TimeUtils.getCurrentUsefulDateTime())
                .orderByDesc(StationQuality::getTimestamp)
                .last("limit 24");
        List<StationQuality> list = this.list(wrapper);
        if (ObjectUtils.isEmpty(list)) {
            throw new RException(E.StationIdNotFoundException);
        }
        if(list.size()<24) {
            int i =24- list.size();
            LambdaQueryWrapper<TableRange> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.orderByDesc(TableRange::getFrom)
                            .last("limit 1");
            TableRange one = rangeService.getOne(queryWrapper);
            SecurityContextHolder.setTableName(one.getTableName());
            LambdaQueryWrapper<StationQuality> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper
                    .eq(StationQuality::getStationCode,id)
                    .orderByDesc(StationQuality::getTimestamp).last("limit "+i);
            List<StationQuality> stationQualities = this.list(lambdaQueryWrapper);
            list.addAll(stationQualities);
        }
        list.sort((o1, o2) ->o1.getTimestamp().compareTo(o2.getTimestamp()));
        SecurityContextHolder.remove();
        return list;
    }

    @Override
    public LocalDateTime getLastUpdateTime() {
        SecurityContextHolder.setTableName(areaCodeList.getTableName());
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(StationQuality::getTimestamp)
                .last("limit 1");
        return this.getOne(wrapper).getTimestamp();
    }

    @Override
    public List<StationQuality> getHistory(StationRenderPost post) {
        LocalDateTime from = TimeUtils.getDivisionDateTime(post.getType());
        LocalDateTime to = TimeUtils.getCurrentUsefulDateTime();
        List<String> tableName = rangeService.getAllTableName(from, to);
        //获取当前站点历史数据
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationQuality::getStationCode, post.getId())
                .ge(StationQuality::getTimestamp, from)
                .and(i -> i
                        .le(StationQuality::getTimestamp, to));
        SecurityContextHolder.setTableName(tableName);
        List<StationQuality> list = this.list(wrapper);
        list.sort((o1, o2) -> o1.getTimestamp().compareTo(o2.getTimestamp()));
        SecurityContextHolder.remove();
        return list;
    }

    @Override
    public IPage<StationQuality> getHistory(String id, List<LocalDateTime> timeRange, Integer current, Integer size) {
        LocalDateTime from = timeRange.get(0);
        LocalDateTime to = timeRange.get(1);
        List<String> tableName = rangeService.getAllTableName(from, to);
        //获取当前站点历史数据
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationQuality::getStationCode, id)
                .ge(StationQuality::getTimestamp, from)
                .and(i -> i
                        .le(StationQuality::getTimestamp, to));
        SecurityContextHolder.setTableName(tableName);
        List<StationQuality> result = this.list(wrapper);
        SecurityContextHolder.remove();
        Page<StationQuality> page = Page.of(current, size);
        //根据参数进行分页
        if (ObjectUtil.isNotEmpty(result)) {
            int total = result.size();
            //防止越界
            int[] range = PageUtils.getPageRange(current, size, total);
            page.setRecords(result.subList(range[0], range[1]));
            page.setTotal(total);
        } else {
            page.setTotal(0);
        }
        return page;
    }

    @Override
    public List<StationQuality> getHistory(String id, List<LocalDateTime> timeRange) {
        LocalDateTime from = timeRange.get(0);
        LocalDateTime to = timeRange.get(1);
        List<String> tableName = rangeService.getAllTableName(from, to);
        //获取当前站点历史数据
        LambdaQueryWrapper<StationQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StationQuality::getStationCode, id)
                .ge(StationQuality::getTimestamp, from)
                .and(i -> i
                        .le(StationQuality::getTimestamp, to));
        SecurityContextHolder.setTableName(tableName);
        List<StationQuality> list = this.list(wrapper);
        SecurityContextHolder.remove();
        return list;
    }
}
